<?php
ini_set('date.timezone','Asia/Shanghai');

require_once 'config.php';
require_once 'regexUtil.php';
define("UMF_PAY_REQ_URL","http://pay.soopay.net/spay/pay/payservice.do");
define("UMF_METHOD_GET","get");
define("UMF_METHOD_POST","post");
define("UMF_PUBLIC_KEY","-----BEGIN CERTIFICATE-----
MIIDNDCCAp2gAwIBAgICLVkwDQYJKoZIhvcNAQEFBQAwPTEOMAwGA1UEBhMFQ0hJ
TkExKzApBgNVBAMTIkNISU5BVEVMRUNPTSBDRVJUSUZJQ0FURSBBVVRIT1JJVFkw
HhcNMDEwMzIxMTA0NzEzWhcNMDMwMzIxMTA0NzEzWjBcMQswCQYDVQQGEwJDTjER
MA8GA1UEChMItPPBrLXn0MUxETAPBgNVBAgTCFNoZW55YW5nMRQwEgYDVQQDEwsx
OTIuMTY4LjIuMjERMA8GA1UEBxMIU2hlbnlhbmcwgZ8wDQYJKoZIhvcNAQEBBQAD
gY0AMIGJAoGBAMZYC7inporVKJCo0pPWdOBjADxzPRF1719G2YskDHVDEuqt6sBR
WX+65dXs1AVKROKmi6jdzAQSlp7z3brsB4skHMo9sqdQgPolgZvCersKJFHgTbjj
NyCoTyOjwOeRsfcqSJaiehQwPW4fLpNQW/lbvOuFrP8Tn0xWZvOunVPDAgMBAAGj
ggEiMIIBHjAJBgNVHRMEAjAAMEYGA1UdHwQ/MD0wO6A5oDeGNWxkYXA6Ly8yMDIu
MTAzLjY1LjE4L291PWNhLG91PXN5c3RlbSxvdT1jYTEsbz1jdCxjPUNOMC8GCCsG
AQUFBwEBBCMwITAfBggrBgEFBQcwAYYTLDIwMi4xMDMuNjUuMTg6OTAwMzAPBghg
hkgBhvhDDAQDAgEBMBIGCGCGSAGG+EMOBAYWBDI3RjkwGQYIYIZIAYb4QxAEDRYL
MTkyLjE2OC4yLjIwEAYIYIZIAYb4QxEEBBYCTlQwGgYIYIZIAYb4QxkEDhYMOTe9
ybfRt/7O8cb3MBkGCGCGSAGG+EMbBA0WCzE5Mi4xNjguMi4yMA8GCGCGSAGG+EMa
BAMCAQMwDQYJKoZIhvcNAQEFBQADgYEAckkH/Vem5+kXPSGgkowjPwv47XXNbD0h
GRMTVXm5PC2kY/wNApQh3lv7Tf5k3UQEoFBACxf6XJtuxf6S0uKBS4ySMKdpbMbO
Uvtwu6ycQUQTRAs1EBgoh1zyuafU2D3iyHQM8etHxaSePXZOZXFkkvBJemyPz23H
AyIn5SKQ2Es=
-----END CERTIFICATE-----");

//子商户入网
define("UMF_RESTPAY_AUTHORIZE","https://pay.soopay.net/spay_restPay/oauth/authorize");
define("UMF_RESTPAY_ADDCHILDMERINFO","https://pay.soopay.net/spay_restPay/addChildMerInfo");
define("UMF_RESTPAY_UPLOADCHILDFILE","https://pay.soopay.net/spay_restPay/uploadChildFile");
define("UMF_RESTPAY_CHANGECHILDREBUT","https://pay.soopay.net/spay_restPay/changeChildRebut");
define("UMF_RESTPAY_SELECTCHILDMERSTATE","https://pay.soopay.net/spay_restPay/selectChildMerState");


/**
 * 数据签名,验签处理工具类
 */
Class SignUtil{
	/**
	 * @param $plain		string 签名明文串
	 * @param $merId		string 商户号
	 * @return bool|string	签名base64编码后的字符串
	 */
    public static function sign($plain,$merId){
    	$log = new Logger();
    	try{
			$priv_key_file = UmfService::$privateKeyPath[$merId];
			$log->logInfo("[UMF SDK]私钥文件绝对路径 ".$priv_key_file);
		    if(!file_exists($priv_key_file)){
				$log->logInfo("[UMF SDK]传入的私钥文件不存在,私钥文件绝对路径 ".$priv_key_file);
				die("[UMF SDK]传入的私钥文件不存在,私钥文件绝对路径 ".$priv_key_file);
		    }
		    $fp = fopen($priv_key_file,"rb");
		    $priv_key = fread($fp, 8192);
		    @fclose($fp);
		    $pkeyid = openssl_get_privatekey($priv_key);
		    if(!is_resource($pkeyid)){ return FALSE;}
		    // compute signature
		    @openssl_sign($plain, $signature, $pkeyid);
		    // free the key from memory
		    @openssl_free_key($pkeyid);
			$log->logInfo("[UMF SDK]签名前明文 " .$plain);
			$log->logInfo("[UMF SDK]签名后密文 " .base64_encode($signature));
		    return base64_encode($signature);
    	}catch(Exception $e){
    		die("[UMF SDK]签名失败".$e->getMessage());
    	}
    }

	/**
	 * @param $plain		string 签名明文串
	 * @param $merId		string 商户号
	 * @return bool|string	签名base64编码后的字符串
	 */
	public static function sign256($plain,$merId){
		$log = new Logger();
		try{
			$priv_key_file = UmfService::$privateKeyPath[$merId];
			$log->logInfo("[UMF SDK]私钥文件绝对路径 ".$priv_key_file);
			if(!file_exists($priv_key_file)){
				$log->logInfo("[UMF SDK]传入的私钥文件不存在,私钥文件绝对路径 ".$priv_key_file);
				die("[UMF SDK]传入的私钥文件不存在,私钥文件绝对路径 ".$priv_key_file);
			}
			$fp = fopen($priv_key_file,"rb");
			$priv_key = fread($fp, 8192);
			@fclose($fp);
			$pkeyid = openssl_get_privatekey($priv_key);
			if(!is_resource($pkeyid)){ return FALSE;}
			// compute signature
			@openssl_sign($plain, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
			// free the key from memory
			@openssl_free_key($pkeyid);
			//$log->logInfo("[UMF SDK]签名前明文 " .$plain);
			$log->logInfo("[UMF SDK]签名后密文 " .base64_encode($signature));
			return base64_encode($signature);
		}catch(Exception $e){
			die("[UMF SDK]签名失败".$e->getMessage());
		}
	}

	/**
	 * @param $plain		string 验签明文
	 * @param $signature	string 验签密文
	 * @return bool			验签结果
	 */
   	public static function verify($plain,$signature){
		//$cert_file = UmfService::$publicKeyPath;
		$log = new Logger();
		//$log->logInfo("[UMF SDK]公钥文件绝对路径 ".$cert_file);
   	 	//if(!file_exists($cert_file)){
		//	$log->logInfo("[UMF SDK]传入的公钥文件不存在,公钥文件绝对路径 ".$cert_file);
		//	die("[UMF SDK]传入的公钥文件不存在,公钥文件绝对路径 ".$cert_file);
		//}
		$log->logInfo("[UMF SDK]异步通知验签明文 ".$plain);
		$log->logInfo("[UMF SDK]异步通知验签密文 ".$signature);
	    $signature = base64_decode($signature);
	    //$fp = fopen($cert_file,"r");
	    //$cert = fread($fp, 8192);
		$cert = UMF_PUBLIC_KEY;
	    //fclose($fp);
	    $pubkeyid = openssl_get_publickey($cert);
	    if(!is_resource($pubkeyid)){return FALSE;}
	    $ok = openssl_verify($plain,$signature,$pubkeyid);
	    @openssl_free_key($pubkeyid);
	    if ($ok == 1) {
			$log->logInfo("[UMF SDK]验签成功");
	        return true;
	    } elseif ($ok == 0) {
			$log->logInfo("[UMF SDK]验签失败");
	        return false;
	    } else {
			$log->logInfo("[UMF SDK]验签失败");
	        return false;
	    }
	 }

	public static function verify256($plain,$signature){
		$log = new Logger();
		$signature = base64_decode($signature);
		$cert = UMF_PUBLIC_KEY;
		$pubkeyid = openssl_get_publickey($cert);
		if(!is_resource($pubkeyid)){return FALSE;}
		$ok = openssl_verify($plain,$signature,$pubkeyid,OPENSSL_ALGO_SHA256);
		@openssl_free_key($pubkeyid);
		if ($ok == 1) {
			$log->logInfo("[UMF SDK]验签成功");
			return true;
		} elseif ($ok == 0) {
			$log->logInfo("[UMF SDK]验签失败");
			return false;
		} else {
			$log->logInfo("[UMF SDK]验签失败");
			return false;
		}
	}
}


/**
 * RSA加解密工具类
 */
class RSACryptUtil {
	/**
	 * 使用公钥对明文字符串进行加密
	 * @param $data 	string 明文
	 * @return string   string 密文
	 */
	public static function encrypt($data) {
		$log = new Logger ();
		//$cert_file = UmfService::$publicKeyPath;
		//$log->logInfo("[UMF SDK]公钥文件绝对路径 ".$cert_file);
		//if(!file_exists($cert_file)){
		//	$log->logInfo("[UMF SDK]传入的公钥文件不存在,公钥文件绝对路径 ".$cert_file);
		//	die("[UMF SDK]传入的公钥文件不存在,公钥文件绝对路径 ".$cert_file);
		//}
		//$fp = fopen($cert_file,"r");
		//$public_key = fread($fp,8192);
		$public_key = UMF_PUBLIC_KEY;
		//fclose($fp);
		$public_key = openssl_get_publickey($public_key);
		openssl_public_encrypt($data,$crypttext,$public_key);
		$encryptDate = base64_encode($crypttext);
		//$log->logInfo ( "[UMF SDK]敏感信息加密前明文: " . $data);
		$log->logInfo ( "[UMF SDK]敏感信息加密后密文: " . $encryptDate);
		return $encryptDate;
	}

	/**
	 * @param $data		string 密文
	 * @param $merId	string 商户号
	 * @return string	string 明文
	 */
	public function decrypt($data,$merId) {
		$log = new Logger ();
		$priv_key_file = UmfService::$privateKeyPath[$merId];
		$log->logInfo("[UMF SDK]私钥文件绝对路径 ".$priv_key_file);
		if(!file_exists($priv_key_file)){
			$log->logInfo("[UMF SDK]传入的私钥文件不存在,私钥文件绝对路径 ".$priv_key_file);
			die("[UMF SDK]传入的私钥文件不存在,私钥文件绝对路径 ".$priv_key_file);
		}
	   	$fp = fopen($priv_key_file,"r");
	   	$private_key = fread($fp,8192);
		fclose ($fp);
		$private_key = openssl_get_privatekey($private_key);
		openssl_private_decrypt(base64_decode($data), $decrypted, $private_key);
		$decryptDate =iconv("GBK", "UTF-8", $decrypted);
		$log->logInfo ( "[UMF SDK]敏感信息解密前密文: " . $data);
		//$log->logInfo ( "[UMF SDK]敏感信息解密后明文: " . $decryptDate);
		return $decryptDate;
	}
}



/**
 * 模拟实现HashMap
 */
Class HashMap{
	var $H_table;

	public function __construct() {
		$this->H_table = array ();
	}

	public function getInnerArr(){
		return $this->H_table;
	}

	/*
	 *向HashMap中添加一个键值对
	 *@param $key	插入的键
 	 *@param $value	插入的值
	 */
	public function put($key, $value) {
		if (!array_key_exists($key, $this->H_table)) {
		   	$this->H_table[$key] = $value;
		   	return null;
		} else {
		   	$tempValue = $this->H_table[$key];
		   	$this->H_table[$key] = $value;
		   	return $tempValue;
		}
	}
	 
	/*
	 * 根据key获取对应的value
	 * @param $key
	 */
	public function get($key) {
		if (array_key_exists($key, $this->H_table)){
			return $this->H_table[$key];
		}
		else{
			return null;
		}
	}

	/*
	 * 删除指定key的键值对
	 * @param $key	要移除键值对的key
	 */
	 public function remove($key) {
		 $temp_table = array ();
	  	 if (array_key_exists($key, $this->H_table)) {
	   	 	$tempValue = $this->H_table[$key];
	   	 	while ($curValue = current($this->H_table)) {
	    		if (!(key($this->H_table) == $key)){
	     			$temp_table[key($this->H_table)] = $curValue;
				}
	    		next($this->H_table);
	   	 	}
	   	 	$this->H_table = null;
	   	 	$this->H_table = $temp_table;
	   	 	return $tempValue;
	  	 } else {
			 return null;
		 }
	 }
	 
	 /**
	  * 获取HashMap的所有键
	  */
	 public function keys(){
	 	return array_keys($this->H_table);
	 }

	 /**
	  * 获取HashMap的所有value值
	  */
	 public function values(){
	 	return array_values($this->H_table);
	 }
	 
	 /**
	  * 将一个HashMap的值全部put到当前HashMap中
	  * @param $map
	  */
	 public function putAll($map){
		 if(!$map->isEmpty()&& $map->size()>0){
			 $keys = $map->keys();
			 foreach($keys as $key){
				 $this->put($key,$map->get($key));
			 }
		 }
	 }
	 
	 /**
	  * 移除HashMap中所有元素
	  */
	 public function removeAll() {
		 $this->H_table = null;
		 $this->H_table = array ();
	 }

	 /*
	  * HashMap中是否包含指定的值
	  * @param $value
	  */
	 public function containsValue($value) {
		  while ($curValue = current($this->H_table)) {
			  if ($curValue == $value) {
				  return true;
			  }
			  next($this->H_table);
		  }
		  return false;
	 }

	 /*
	  * HashMap中是否包含指定的键key
	  * @param $key
	  */
	 public function containsKey($key) {
		  if (array_key_exists($key, $this->H_table)) {
			  return true;
		  } else {
			  return false;
		  }
	 }

	 /*
	  * 获取HashMap中元素个数
	  */
	 public function size() {
		 return count($this->H_table);
	 }
	
	 
	 /*
	  * 判断HashMap是否为空
	  */
	 public function isEmpty() {
		 return (count($this->H_table) == 0);
	 }

	 public function toString() {
		 print_r($this->H_table);
	 }
}




/**
 * 字符串处理工具类
 */
Class StringUtil
{
	/**
	 * @param $map HashMap 使用&符号组织签名明文串排序a-z 包含sign_type字段 做了urlencode
	 * @return string
	 */
	public static function getPlainSortByAndWithSignType($map)
	{
		$arg = "";
		$paramter = array();
		if ((!$map->isEmpty()) && ($map->size() > 0)) {
			$keys = $map->keys();
			foreach ($keys as $key) {
				//sign_type 不需要参与RAS签名
				$paramter[$key . "=" . urlencode(trim($map->get($key)))] = $key . "=" . urlencode(trim($map->get($key)));
			}
			//字母a到z排序后的数组
			$sort_array = StringUtil::arg_sort($paramter);
			while (list ($key, $val) = each($sort_array)) {
				$arg .= $val . "&";
			}
			$arg = substr($arg, 0, count($arg) - 2); //去掉最后一个&字符
			return $arg;
		} else {
			die ("[UMF SDK]获取请求参数明文字符串失败:传入参数为空!");
		}
	}

	/**
	 * @param $map HashMap 使用&符号组织签名明文串排序a-z 去除sign_type字段 不做urlencode
	 * @return string
	 */
	public static function getPlainSortByAndWithoutSignType($map)
	{
		$arg = "";
		$paramter = array();
		if ((!$map->isEmpty()) && ($map->size() > 0)) {
			$keys = $map->keys();
			foreach ($keys as $key) {
				//sign_type 不需要参与RAS签名
				if ("sign_type" != $key) {
					$paramter[$key . "=" . trim($map->get($key))] = $key . "=" . trim($map->get($key));
				}
			}
			//字母a到z排序后的数组
			$sort_array = StringUtil::arg_sort($paramter);
			while (list ($key, $val) = each($sort_array)) {
				$arg .= $val . "&";
			}
			$arg = substr($arg, 0, count($arg) - 2); //去掉最后一个&字符
			return $arg;
		} else {
			die ("[UMF SDK]获取请求参数明文字符串失败:传入参数为空!");
		}
	}

	/**
	 * 去除字符串前后空格,如果字符串为null则返回空串""
	 */
	public static function trim($str){
		if ($str == null) {
			return "";
		} else {
			return trim($str);
		}
	}

	/**
	 * @param $array array() 对数组进行a-z升序排列
	 * @return mixed
	 */
	public static function arg_sort($array){
		asort($array);
		return $array;
	}

	public static function String2Hex($string){
		$hex='';
		for ($i=0; $i < strlen($string); $i++){
			$hex .= dechex(ord($string[$i]));
		}
		return $hex;
	}

	public static function Hex2String($hex){
		$string='';
		for ($i=0; $i < strlen($hex)-1; $i+=2){
			$string .= chr(hexdec($hex[$i].$hex[$i+1]));
		}
		return $string;
	}
}



/**
 * 日志处理类
 */
Class Logger{
	public function logInfo($msg){
		if(UMF_LOG_SWITCH == true){
			$filePath = UMF_LOG_PATH ."-". date("Ymd").".txt";
			$msgHead = date("[Y-m-d H:i:s]"). "-[".$_SERVER['HTTP_REFERER']."]-[data] ";
			$msg = $msgHead .$msg."\n";
			error_log($msg, 3, $filePath);
		}
	}

	public function logArrToStr($arr=array()){
		$str = "\nArray(\n";
		foreach($arr as $key=>$value){
			$tmpStr = $key ." = " .$value . "\n";
			$str .= "\t".$tmpStr;
		}
		$str .= ")";
		return $str;
	}
}



/**
 * 请求参数校验 加解密工具类
 */
Class CheckReqDataAndEncrypt{
	/**
	 * @param $map HashMap 参数校验
	 */
	public static function doCheck($map) {
		$log = new Logger();
		$service = $map->get ("service");
		$serviceRuleMap = regexUtil::$serviceRule;
		//service对应的必填字段校验
		$paramStr = StringUtil::trim($serviceRuleMap[$service]);
		if($paramStr!=null && strlen($paramStr)>0) {
			//该service对应的必传字段数组
			$arr = explode(",",$paramStr);
			foreach ($arr as $key) {
				if (""==$map->get($key) || null==$map->get($key)) {
					$log->logInfo("[UMF SDK]请求接口 service = ".$service." 的参数值 ".$key ." 不能为空");
					$log->logInfo("--------------------log end---------------------");
					die("[UMF SDK]请求接口 service = ".$service." 的参数值 ".$key ." 不能为空");
				}
			}
			// 历史订单查询接口mer_order_info_query trade_no和order_id这两个字段必填字段传一个即可
			if($service == "mer_order_info_query"){
				$order_id = $map->get ("order_id");
				$trade_no = $map->get ("trade_no");
				if((""==$order_id||null==$order_id) && (""==$trade_no||null==$trade_no)){
					$log->logInfo("[UMF SDK]请求接口 service = ".$service." 的参数值 "."order_id 和 trade_no" ." 不能同时为空");
					$log->logInfo("--------------------log end---------------------");
					die("[UMF SDK]请求接口 service = ".$service." 的参数值 "."order_id 和 trade_no" ." 不能同时为空");
				}
			}
		}

		$ruleMap = regexUtil::$reqRule;
		$ruleMapKeys = array_keys($ruleMap);
		$mapKeys = $map->keys();
		foreach($mapKeys as $key){
			$value = StringUtil::trim($map->get($key));
			if(!self::containsValue($key,$ruleMapKeys)){ // 字段不需要正则校验情形
				continue;
			}
			else if(self::containsValue($key,$ruleMapKeys)){ // 字段需要正则校验情形
				$regex = $ruleMap[$key];
				if(""!=$value && null!=$value && !empty($regex)){
					if(preg_match($regex, $value)){
						$log->logInfo("[UMF SDK]请求接口 service = ".$service." 的参数值 ".$key ." 正则校验通过");
					} else {
						$log->logInfo("[UMF SDK]请求接口 service = ".$service." 的参数值 ".$key ." 正则校验未通过,对应的正则表达式为 regex = " . $regex);
						$log->logInfo("--------------------log end---------------------");
						die("[UMF SDK]请求接口 service = ".$service." 的参数值 ".$key ." 正则校验未通过,对应的正则表达式为 regex = " . $regex);
					}
				}
			}
		}
	}

	/*
	 * $arr中是否包含$value
	 */
	public static function containsValue($value,$arr) {
		while ($curValue = current($arr)) {
			if ($curValue == $value) {
				return true;
			}
			next($arr);
		}
		return false;
	}

	/**
	 * 敏感字段加密
	 */
	public static function doEncrypt($map) {
		$log = new Logger ();
		$chkKeys = array(
			"card_id",
			"valid_date",
			"cvv2",
			"pass_wd",
			"identity_code",
			"card_holder",
			"recv_account",
			"recv_user_name",
			"identity_holder",
			"identityCode",
			"cardHolder",
			"mer_cust_name",
			"account_name",
			"bank_account",
			"endDate",
			"tax_mer_name",
		);
		foreach($chkKeys as $key){
			$value = StringUtil::trim($map->get($key));
			if(""==$value || null==$value){
				continue;
			}
			$log->logInfo("[UMF SDK]请求接口 service = ".$map->get("service")." 的参数值 ".$key ." 是敏感字段需要进行RSA加密");
			$value=iconv("UTF-8", "GBK", $value);
			$value = RSACryptUtil::encrypt ( $value );
			$map->put($key,$value);
		}
		return $map;
	}
}


class JsonUtil{
	public static function arrayToJson($paramsArr=array()){
		$map = new HashMap();
		foreach($paramsArr as $key => $value){
			$map->put($key,$value);
		}
		$paramter = array();
		$keys = $map->keys();
		foreach ($keys as $key) {
			$paramter[$key."=".trim($map->get($key))] = "\"".$key."\":\"".trim($map->get($key))."\",";
		}
		//字母a到z排序后的数组
		$sort_array = StringUtil::arg_sort($paramter);
		$json = "";
		while (list ($key, $val) = each($sort_array)) {
			$json .= $val;
		}
		$json = substr($json, 0, count($json) - 2); //去掉最后一个 , 字符
		$json = "{".$json."}";
		return $json;
	}

}

?>


